const { translateFilters } = require("../../display/filters")
const { Display, translateBloon, translateValue } = require("../../display/general")
const { ignoreFunction } = require("../../util/ignore")
const { getModelType, diagonalLength } = require("../../util/utils")
const { parseAttack } = require("../attack/parse")
const { parseFilters } = require("../filter/parse")
const { parseProjectileBehavior } = require("../projectile/behavior")
const { parseProjectile } = require("../projectile/parse")

const models = {}

models.MonkeyFanClubModel = (b, a) => {
    a.buffs.push({
        maxTier: b.maxTier,
        count: b.towerCount,
        additionalDamage: b.bonusDamage ? Display.additive(b.bonusDamage) : null,
        additionalPierce: b.bonusPierce ? Display.additive(b.bonusPierce) : null,
        damageType: b.immuneBloonProperties ? b.immuneBloonProperties : null,
        cooldownMultiplier: Display.multiplier(b.reloadModifier),
        towerRange: b.range,
        projectileRadius: b.projectileRadius,
        lifespan: Display.time(b.lifespan)
    })
}

models.TurboModel = (b, a) => {
    a.buffs.push({
        cooldownMultiplier: Display.percent(b.multiplier),
        additionalDamage: b.extraDamage ? Display.additive(b.extraDamage) : null,
        projectileRadiusMultiplier: b.projectileRadiusScaleBonus ? Display.additivePercent(b.projectileRadiusScaleBonus) : null,
        lifespan: Display.time(b.lifespan)
    })
}

models.DamageUpModel = (b, a) => {
    a.buffs.push({
        mutationId: Display.mutationId(b.Mutator.id),
        additionalDamage: Display.additive(b.additionalDamage),
        lifespan: Display.time(b.lifespanFrames / 60)
    })
}

models.ActivateAttackModel = (b, a) => {
    const result = []
    b.attacks.forEach(e => {
        const attacks = parseAttack(e)
        result.push(...attacks.map(e => {
            if (b.isOneShot) {
                e.attackCooldown = null
                e.minAttackCooldown = null
            } else {
                e.meta.lifespan = Display.time(b.lifespan)
            }
            return e
        }))
    })
    a.attacks.push(...result)
}

models.AbilityDamageAllModel = (b, a) => {
    // TODO: parse this thing
}

models.ActivateRateSupportZoneModel = (b, a) => {
    a.buffs.push({
        mutationId: Display.mutationId(b.mutatorId),
        cooldownMultiplier: Display.multiplierPercent(b.rateModifier),
        filters: translateFilters(parseFilters(b.filters)),
        radius: b.range && b.range < diagonalLength ? b.range : null,
        lifespan: Display.time(b.lifespan),
        notes: [
            b.canEffectThisTower ? translateValue('affectsSelf', 'affects self') : null,
            b.isGlobal || b.range >= diagonalLength ? translateValue('affectGlobal', 'has global range') : null,
        ]
    })
}

models.TakeAimModel = (b, a) => {
    a.buffs.push({
        mutationId: Display.mutationId(b.Mutator.id),
        rangeMultiplier: Display.multiplierPercent(b.rangeModifier),
        spreadMultiplier: Display.multiplierPercent(b.spreadModifier),
        immunitiesGranted: b.immunitiesGranted ? b.immunitiesGranted.split(',').map(e => e.toLowerCase().trim()).map(translateBloon).join('/') : null,
        lifespan: Display.time(b.lifespanFrames / 60)
    })
}

models.MarkedToPopModel = (b, a) => {
    const markingAttack = parseAttack(b.markingAttackModel)[0]
    markingAttack.meta.lifespan = Display.time(b.markingTimeFrames / 60)
    const executionAttack = parseAttack(b.executionAttackModel)[0]
    executionAttack.meta.lifespan = Display.time(b.executionTimeMaxFrames / 60)
    a.attacks.push(markingAttack, executionAttack)
}

models.ActivateAbilitiesOnAbilityModel = ignoreFunction

models.RedeployModel = ignoreFunction

models.FindDeploymentLocationModel = ignoreFunction

models.AbilityCreateTowerModel = (b, a) => {
    const { parseTower } = require("../tower/parse")
    a.towers.push(parseTower(b.towerModel))
}

models.MutateRemoveAllAttacksOnAbilityActivateModel = ignoreFunction

models.DarkshiftModel = ignoreFunction

models.ImmunityModel = (b, a) => {
    a.meta.lifespan = b.lifespan
}

models.ActivateRangeSupportZoneModel = (b, a) => {
    a.buffs.push({
        mutationId: Display.mutationId(b.mutatorId),
        rangeMultiplier: b.multiplier && b.multiplier !== 1 ? Display.multiplier(b.multiplier) : null,
        additionalRange: b.additive ? Display.additive(b.additive) : null,
        filters: translateFilters(parseFilters(b.filters)),
        lifespan: Display.time(b.lifespan)
    })
}

models.ActivateDamageModifierSupportZoneModel = (b, a) => {
    if (!b.damageModifierModel) return
    const fakeProj = { damageMods: [] }
    parseProjectileBehavior(b.damageModifierModel, fakeProj)
    a.buffs.push({
        mutationId: Display.mutationId(b.mutatorId),
        damageMods: fakeProj.damageMods,
        filters: translateFilters(parseFilters(b.filters)),
        lifespan: Display.time(b.lifespan)
    })
}

models.IncreaseRangeModel = (b, a) => {
    a.buffs.push({
        mutationId: Display.mutationId(b.Mutator.id),
        additionalRange: b.addative ? Display.additive(b.addative) : null,
        rangeMultiplier: b.multiplier && b.multiplier !== 1 ? b.multiplier : null,
        lifespan: Display.time(b.lifespanFrames / 60)
    })
}

models.MorphTowerModel = (b, a) => {
    const { parseTower } = require("../tower/parse")
    a.towers.push(parseTower(b.secondaryTowerModel))
    a.meta.maxTier = b.maxTier
    a.meta.count = b.maxTowers
    a.meta.lifespan = Display.time(b.lifespan)
}

models.CashPerBananaFarmInRangeModel = (b, a) => {
    a.meta.cash = b.baseCash
    a.meta.cashIncreasePerBananaFarmInRange = Display.additive(b.cash)
}

models.BonusLivesOnAbilityModel = (b, a) => {
    a.meta.lives = b.amount
}

models.ImfLoanModel = (b, a) => {
    a.meta.loan = b.amount
    a.meta.recoveryRate = Display.percent(b.incomeRecoveryRate)
}

models.CallToArmsModel = (b, a) => {
    a.buffs.push({
        mutationId: Display.mutationId(b.Mutator.id),
        multiplier: Display.multiplier(b.multiplier),
        lifespan: Display.time(b.lifespan),
        notes: [b.useRadius ? null : translateValue('affectGlobal', 'has global range')]
    })
}

models.OverclockModel = (b, a) => {
    a.buffs.push({
        mutationId: Display.mutationId(b.mutatorId),
        cooldownMultiplier: Display.multiplierPercent(b.rateModifier),
        villageRangeModifier: Display.multiplierPercent(b.villageRangeModifier),
        lifespan: Display.time(b.lifespanFrames / 60),
        paragonZoneRange: b.isParagonMode ? b.paragonZoneRange : null,
        paragonZoneLifespan: b.isParagonMode ? Display.time(b.paragonZoneLifespanFrames / 60) : null,
    })
}

models.OverclockPermanentModel = (b, a) => {
    a.buffs.push({
        cooldownMultiplierPerStack: Display.additivePercent(1 - b.rateModifier),
        villageRangeModifierPerStack: Display.additivePercent(b.villageRangeModifier - 1),
        maxStacks: b.maxStacks
    })
}

//----------------------------------------------------
// paragons
//----------------------------------------------------

models.EruptionModel = (b, a) => {
    a.buffs.push({
        projectileLifespanMultiplier: Display.multiplier(b.projectileLifespanMult),
    })
}

models.AbilityReduceCooldownOnLivesLostModel = (b, a) => {
    // TODO: parse this thing
}

models.FinalStrikeModel = (b, a) => {
    a.attacks.push({
        projectile: parseProjectile(b.projectileModel),
    })
}

models.CarpetBombAbilityModel = (b, a) => {
    const proj = parseProjectile(b.projectileModel)
    proj.emission.count = b.numProjectiles
    a.projectile.push(proj)
}

models.ArcaneMetamorphosisModel = (b, a) => {
    a.meta.manaPerSecond = b.manaPerSecond
}

models.PhoenixRebirthModel = (b, a) => {
    a.attacks.push({
        projectile: [
            parseProjectile(b.projectileExplosionModel),
            parseProjectile(b.projectileZOMG),
        ],
        lifespan: Display.time(b.duration)
    })
}

models.SpikeaggedonModel = (b, a) => {
    a.projectile.push(parseProjectile(b.projectileModel))
}

models.ActivateAttackCreateTowerPlacementModel = (b, a) => {
    //TODO: rework
    a.attacks.push(...b.attacks.map(parseAttack))
}

//----------------------------------------------------
// heroes
//----------------------------------------------------
models.ActivateTempTargetPrioSupportZoneModel = (b, a) => {
    a.buffs.push({
        mutationId: Display.mutationId(b.mutatorId),
        spreadMultiplier: Display.multiplierPercent(1 - b.accuracyImprovementPercent),
        lifespan: Display.time(b.lifespan)
    })
}

models.ArtilleryCommandModel = (b, a) => {
    if (b.givesBuff) {
        a.meta.lifespan = Display.time(b.buffFrames / 60)
    }
}

models.ChangeDamageTypeModel = (b, a) => {
    a.buffs.push({
        damageType: b.immuneBloonProperties,
        lifespan: Display.time(b.lifespanFrames / 60)
    })
}

models.MutateProjectileOnAbilityModel = (b, a) => {
    const fakeProj = { damageMods: [], behaviors: [], meta: {} }
    parseProjectileBehavior(b.projectileBehaviorModel, fakeProj)
    a.buffs.push({
        mutationId: Display.mutationId(b.mutatorId),
        additionalDamage: b.damageIncrease ? Display.additive(b.damageIncrease) : null,
        damageMods: fakeProj.damageMods.length > 0 ? fakeProj.damageMods : null,
        meta: fakeProj.meta,
        lifespan: Display.time(b.lifespanFrames / 60)
    })
}

models.MutateCreateProjectileOnExhaustPierceOnAbilityModel = (b, a) => {
    a.buffs.push({
        count: Display.additive(b.countIncrease),
        lifespan: Display.time(b.lifespanFrames / 60)
    })
}

models.MoabBarrageModel = (b, a) => {
    a.meta.statuses = {
        mutationId: b.mutatorId,
        damage: b.damageOverTimeModel.damage,
        interval: b.damageOverTimeModel.interval,
        maxCount: b.targets,
        lifespan: Display.time(b.durationFrames / 60),
    }
}

models.MutateDamageOnAbilityModel = (b, a) => {
    a.buffs.push({
        mutationId: Display.mutationId(b.Mutator.id),
        additionalDamage: b.damageIncrease ? Display.additive(b.damageIncrease) : null,
        lifespan: Display.time(b.lifespanFrames / 60)
    })
}

models.BiohackModel = (b, a) => {
    a.buffs.push({
        mutationId: [
            Display.mutationId(b.DamageMutator.id),
            Display.mutationId(b.BehaviorMutator.id),
            Display.mutationId(b.behaviors[0].Mutator.id)
        ],
        additionalDamage: Display.additive(b.damageIncrease),
        count: b.affectedCount,
        lifespan: Display.time(b.lifespan),
        shutoffLifespan: Display.time(b.behaviors[0].shutoffTime)
    })
}

models.SyphonFundingModel = (b, a) => {
    a.meta.lifespan = Display.time(b.lifespan)
}

models.ActivateTowerDamageSupportZoneModel = (b, a) => {
    a.buffs.push({
        mutationId: Display.mutationId(b.mutatorId),
        additionalDamage: b.damageIncrease !== 0 ? Display.additive(b.damageIncrease) : null,
        range: b.isGlobal || b.range >= diagonalLength ? null : b.range,
        damageType: b.replaceImmuneBloonProperties ? b.immuneBloonProperties : null,
        filters: translateFilters(parseFilters(b.filters)),
        lifespan: Display.time(b.lifespan),
        notes: [
            b.canEffectThisTower ? translateValue('affectsSelf', 'affects self') : null,
            b.isGlobal || b.range >= diagonalLength ? translateValue('affectGlobal', 'has global range') : null,
        ]
    })
}

models.PauseAllOtherAttacksModel = (b, a) => {
    a.meta.pauseOtherAttackLifespan = Display.time(b.lifespan)
}

models.LongArmOfLightModel = (b, a) => {
    a.buffs.push({
        mutationId: Display.mutationId(b.mutatorId),
        projectileSpeedMultiplier: Display.multiplierPercent(b.multiplier),
        damageMultiplier: Display.multiplierPercent(b.multiplier),
        projectileRadiusMultiplier: Display.multiplierPercent(b.multiplier),
        additionalDamage: b.damageIncrease > 0 ? Display.additive(b.damageIncrease) : null,
        damageType: b.immuneBloonProperties,
        lifespan: Display.time(b.lifespan)
    })
}

models.BloodSacrificeModel = (b, a) => {
    a.meta.herpXpMultiplier = Display.multiplier(b.xpMultiplier)
    a.buffs.push({
        cooldownMultiplier: Display.multiplierPercent(1 - b.rateBonusMultiplier),
        cooldownMultiplierPerStack: Display.additivePercent(-b.bonusMultiplierPerSacrifice),
        rangeMultiplier: Display.multiplierPercent(1 + b.rangeBonusMultiplier),
        rangeMultiplierPerStack: Display.additivePercent(b.bonusMultiplierPerSacrifice),
        costNeedPerStack: b.bonusSacrificeAmount,
        maxStacks: b.maxBonusCount,
        lifespan: Display.time(b.buffDuration)
    })
}

models.ActivatePierceSupportZoneModel = (b, a) => {
    a.buffs.push({
        mutationId: Display.mutationId(b.mutatorId),
        additionalPierce: b.pierceIncrease ? Display.additive(b.pierceIncrease) : null,
        filters: translateFilters(parseFilters(b.filters)),
        radius: b.range && b.range < diagonalLength ? b.range : null,
        lifespan: Display.time(b.lifespan),
        notes: [
            b.canEffectThisTower ? translateValue('affectsSelf', 'affects self') : null,
            b.isGlobal || b.range >= diagonalLength ? translateValue('affectGlobal', 'has global range') : null,
        ]
    })
}

models.ActivateVisibilitySupportZoneModel = (b, a) => {
    a.buffs.push({
        mutationId: Display.mutationId(b.mutatorId),
        filters: translateFilters(parseFilters(b.filters)),
        radius: b.range && b.range < diagonalLength ? b.range : null,
        lifespan: Display.time(b.lifespan),
        notes: [
            b.canEffectThisTower ? translateValue('affectsSelf', 'affects self') : null,
            b.isGlobal || b.range >= diagonalLength ? translateValue('affectGlobal', 'has global range') : null,
        ]
    })
}

models.BrickellFreezeMinesAbilityBuffModel = (b, a) => {
    a.buffs.push({
        mutationId: Display.mutationId(b.Mutator.id),
        seamineCooldownMultiplier: Display.multiplierPercent(b.multiplier),
        projectileSpeedMultiplier: Display.multiplierPercent(b.projectileSpeedMultiplier),
        lifespan: Display.time(b.lifespan)
    })
}

models.PlaceProjectileAtModel = (b, a) => {
    a.projectile.push(parseProjectile(b.projectileModel))
}

models.DroneSwarmModel = (b, a) => {
    a.meta.lifespan = Display.time(b.duration)
}

models.UCAVModel = (b, a) => {
    const { parseTower } = require("../tower/parse")
    a.towers.push(parseTower(b.ucavTowerModel))
    a.meta.lifespan = Display.time(b.duration)
}

models.LeapingSwordModel = (b, a) => {
    a.projectile.push(
        parseProjectile(b.impactProjectileModel),
        parseProjectile(b.dotProjectileModel)
    )
}

models.SwordChargeModel = (b, a) => {
    a.projectile.push(parseProjectile(b.projectileModel))
}

models.FlightBoostAbilityModel = (b, a) => {
    a.buffs.push({
        mutationId: Display.mutationId(b.Mutator.id),
        speedMultiplier: Display.multiplierPercent(b.moveSpeedMultiplier),
        lifespan: Display.time(b.lifespan)
    })
}

models.FrozenCascadeModel = (b, a) => {
    a.projectile.push(parseProjectile(b.projectile))
    a.meta.count = b.maxExplosions
}

models.CreateProjectileOnAbilityActivateModel = (b, a) => {
    a.projectile.push(parseProjectile(b.projectile))
}

models.FrozenBurialModel = (b, a) => {

}

function parseAbilityBehavior(b, a, type = null) {
    if (!type) type = getModelType(b)
    if (models[type]) models[type](b, a)
    else a.behaviors.push(b)
}

module.exports = {
    parseAbilityBehavior
}